package com.tbit.uqbike.webmanager.business.machinegroup.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.webmanager.business.machinegroup.object.MachineGroup;
import com.tbit.uqbike.webmanager.business.machinegroup.object.dto.MachineGroupAddDto;
import com.tbit.uqbike.webmanager.business.machinegroup.object.dto.MachineGroupUpdateDto;
import com.tbit.uqbike.webmanager.business.machinegroup.object.vo.MachineGroupVo;
import com.tbit.uqbike.webmanager.business.machinegroup.service.MachineGroupService;
import com.tbit.uqbike.webmanager.business.machinegroup.dao.core.MachineGroupDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 针对表【machinegroup(分组表)】的数据库操作Service实现
 *
 * @author <a href="mailto:zheng.zebiao@tbit.com.cn">zb</a>
 * @since 2024-07-12 17:12:06
 */
@Slf4j
@Service
public class MachineGroupServiceImpl extends ServiceImpl<MachineGroupDao, MachineGroup>
        implements MachineGroupService {


    @Override
    public List<MachineGroupVo> selectListWithCount(Integer accountId, Integer machineType) {
        List<MachineGroupVo> groups = getBaseMapper().selectListWithCount(accountId, machineType);

        return addNoGroupIfNotExist(accountId, groups);
    }

    @Override
    public List<MachineGroupVo> selectListWithCountByIds(Integer accountId, List<Integer> ids) {
        List<MachineGroupVo> groups = getBaseMapper().selectListWithCountByIds(accountId, ids);

        return addNoGroupIfNotExist(accountId, groups);
    }

    private List<MachineGroupVo> addNoGroupIfNotExist(Integer accountId, List<MachineGroupVo> groups) {
        // 如果无分组不存在，则添加
        if (groups.stream().noneMatch(g -> g.getMachineGroupId() == -1)) {
            groups.add(MachineGroupVo.builder()
                    .count(0)
                    .machineGroupId(-1)
                    .groupName("无分组")
                    .accountId(accountId)
                    .createTime(new Date(0))
                    .weight(DEFAULT_GROUP_WEIGHT)
                    .build());
        }

        return groups.stream()
                .sorted(Comparator.comparingInt(MachineGroup::getWeight))
                .collect(Collectors.toList());
    }

    /**
     * 分组权重步长
     */
    private static final int WEIGHT_STEP = 1 << 24;
    /**
     * 默认分组权重（无分组）
     */
    private static final int DEFAULT_GROUP_WEIGHT = 0;

    @Override
    public void add(MachineGroupAddDto dto) {
        if (dto.getAfterGroupId() == null) {
            dto.setAfterGroupId(-1);
        }

        // 限制数量不超过10个（包括无分组）
        if (getBaseMapper().selectCount(Wrappers.lambdaQuery(MachineGroup.class)
                .eq(MachineGroup::getAccountId, dto.getAccountId())) >= 9) {
            throw new BaseException("分组数量已达上限");
        }

        // 获取相邻分组的权重
        List<MachineGroup> nearGroups = getBaseMapper().selectList(Wrappers.lambdaQuery(MachineGroup.class)
                .eq(MachineGroup::getAccountId, dto.getAccountId())
                .ge(MachineGroup::getWeight, Wrappers.lambdaQuery(MachineGroup.class)
                        .select(MachineGroup::getWeight)
                        .eq(MachineGroup::getMachineGroupId, dto.getAfterGroupId())
                )
                .orderByAsc(MachineGroup::getWeight)
                .last("limit 2"));

        MachineGroup addGroup = new MachineGroup();
        addGroup.setGroupName(dto.getGroupName());
        addGroup.setAccountId(dto.getAccountId());
        addGroup.setRemark(dto.getRemark());
        addGroup.setCreateTime(new Date());

        // 计算新分组的权重
        if (dto.getAfterGroupId() == -1) {
            if (nearGroups.isEmpty()) {
                addGroup.setWeight(WEIGHT_STEP);
            } else {
                addGroup.setWeight(DEFAULT_GROUP_WEIGHT + (nearGroups.get(0).getWeight() - DEFAULT_GROUP_WEIGHT) / 2);
            }
        } else {
            if (nearGroups.isEmpty() || !dto.getAfterGroupId().equals(nearGroups.get(0).getMachineGroupId())) {
                throw new BaseException("分组不存在");
            } else if (nearGroups.size() == 1) {
                addGroup.setWeight(nearGroups.get(0).getWeight() + WEIGHT_STEP);
            } else {
                addGroup.setWeight(nearGroups.get(0).getWeight() + (nearGroups.get(1).getWeight() - nearGroups.get(0).getWeight()) / 2);
            }
        }

        save(addGroup);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdate(List<MachineGroupUpdateDto> dtoList) {
        List<MachineGroup> updateGroups = dtoList.stream().map(dto -> {
            MachineGroup updateGroup = new MachineGroup();
            updateGroup.setMachineGroupId(dto.getMachineGroupId());
            updateGroup.setGroupName(dto.getGroupName());
            updateGroup.setRemark(dto.getRemark());
            return updateGroup;
        }).collect(Collectors.toList());

        if (updateBatchById(updateGroups)) {
            log.info("[车辆分组] 更新分组信息成功：{}", dtoList);
        } else {
            log.warn("[车辆分组] 更新分组信息失败或无变化：{}", dtoList);
        }
    }

    @Override
    public Long getMachineGroupCountNotInIds(Integer accountId, List<Integer> machineGroupIds) {
        LambdaQueryWrapper<MachineGroup> wrapper = Wrappers.<MachineGroup>lambdaQuery()
                .eq(MachineGroup::getAccountId, accountId);

        if (CollUtil.isNotEmpty(machineGroupIds)) {
            wrapper = wrapper.notIn(MachineGroup::getMachineGroupId, machineGroupIds);
        }
        return getBaseMapper().selectCount(wrapper);
    }
}




